package mh.map;

import java.awt.Point;
import java.util.HashMap;
import java.util.Properties;

import mh.interfaces.IImage;

/**
 * Each single Layer of the <code>Map</code> that contain only drawable tiles.<br>
 * 
 * @author Gianmarco
 * 
 *         TODO RENAME CORRECT VARS for drawing
 * 
 */
public class MapLayer extends Layer {

	/**
	 * The matrix that contains each tile of this layer. <code>null</code> if the tile is empty.
	 */
	private final IImage[][]				tileMatrix;
	protected HashMap<Object, Properties>	tileInstanceProperties	= new HashMap<Object, Properties>();

	/**
	 * 
	 * @param x
	 *            The initial x position of the sprite when created the map
	 * @param y
	 *            The initial y position of the sprite when created the map
	 * @param width
	 *            The width of the layer
	 * @param height
	 *            The height of the layer
	 */
	public MapLayer(double x, double y, int width, int height) {
		super(x, y, width, height);
		this.tileMatrix = new Tile[height][width];
		//		for (int i = 0; i < 36; i++) {
		//			for (int j = 0; j < 28; j++) {
		//				// ocio che disegno il muro qui
		//								if (i == 4 && j == 3) {
		//									this.tileMatrix[i][j] = ResourceFactory.get().getTile("sprites/ship.gif");
		//								} else if (i == 4 && j == 4) {
		//									this.tileMatrix[i][j] = ResourceFactory.get().getTile("sprites/ship.gif");
		//								} else if (i == 4 && j == 5) {
		//									this.tileMatrix[i][j] = ResourceFactory.get().getTile("sprites/ship.gif");
		//								} else {
		//									this.tileMatrix[i][j] = ResourceFactory.get().getTile("sprites/griglia.gif");
		//								}
		//			}
		//		}
	}

	/**
	 * 
	 * @param x
	 * @param y
	 * @param tip
	 */
	public void setTileInstancePropertiesAt(int x, int y, Properties tip) {
		if (this.bounds.contains(x, y)) {
			Object key = new Point(x, y);
			this.tileInstanceProperties.put(key, tip);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see mh.Layer#draw(double)
	 */
	@Override
	public void draw(long delta) {
		if (this.visible) {
			double offsetX = 0;
			double offsetY = 0;
			double startX = 0;
			double startY = 0;
			if (this.actualx >= CENTRAL_COLUMN) {
				startX = (this.actualx - CENTRAL_COLUMN);
			} else if (this.actualx < CENTRAL_COLUMN) {
				offsetX = (CENTRAL_COLUMN - this.actualx);
			}
			if (this.actualy >= CENTRAL_ROW) {
				startY = (this.actualy - CENTRAL_ROW);
			} else if (this.actualy < CENTRAL_ROW) {
				offsetY = (CENTRAL_ROW - this.actualy);
			}

			for (int i = (int) startY; i < this.tileMatrix.length; i++) {
				for (int j = (int) startX; j < this.tileMatrix[i].length; j++) {
					if (this.tileMatrix[i][j] != null) {
						double xPx = ((j - startX) + offsetX) * TILE_SIZE;
						double yPy = ((i - startY) + offsetY) * TILE_SIZE;
						if ((xPx >= -16) && (xPx <= (VISIBLE_COLUMNS * TILE_SIZE)) && (yPy >= -16) && (yPy <= (VISIBLE_ROWS * TILE_SIZE))) {
							this.tileMatrix[i][j].draw(xPx, yPy); //TODO
						}
					}
				}
			}
			this.lastFrameChange += delta;

			if (this.lastFrameChange > this.frameDuration) {
				this.lastFrameChange = 0;
				if (this.actualx < this.finalx) {
					this.actualx += 0.5;
				} else if (this.actualx > this.finalx) {
					this.actualx -= 0.5;
				} else if (this.actualy < this.finaly) {
					this.actualy += 0.5;
				} else if (this.actualy > this.finaly) {
					this.actualy -= 0.5;
				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see mh.Layer#isAvaible(int, int)
	 */
	@Override
	public boolean isAvaible(int x, int y) {
		// This is a level of tiles, always avaible to the player.
		return true;
	}

	//	/**
	//     * Replaces all occurrences of the Tile <code>find</code> with the Tile
	//     * <code>replace</code> in the entire layer
	//     *
	//     * @param find    the tile to replace
	//     * @param replace the replacement tile
	//     */
	//    public void replaceTile(Tile find, Tile replace) {
	//        for (int y = bounds.y; y < bounds.y + bounds.height; y++) {
	//            for (int x = bounds.x; x < bounds.x + bounds.width; x++) {
	//                if(getTileAt(x,y) == find) {
	//                    setTileAt(x, y, replace);
	//                }
	//            }
	//        }
	//    }
	//	/**
	//     * Returns the first occurrence (using top down, left to right search) of
	//     * the given tile.
	//     *
	//     * @param t the {@link Tile} to look for
	//     * @return A java.awt.Point instance of the first instance of t, or
	//     *         <code>null</code> if it is not found
	//     */
	//    public Point locationOf(Tile t) {
	//        for (int y = bounds.y; y < bounds.height + bounds.y; y++) {
	//            for (int x = bounds.x; x < bounds.width + bounds.x; x++) {
	//                if (getTileAt(x, y) == t) {
	//                    return new Point(x, y);
	//                }
	//            }
	//        }
	//        return null;
	//    }
	/**
	 * Sets the tile at the specified position. Does nothing if (tx, ty) falls outside of this layer.
	 * 
	 * @param tx
	 *            x position of tile
	 * @param ty
	 *            y position of tile
	 * @param ti
	 *            the tile object to place
	 */
	public void setTileAt(int tx, int ty, Tile ti) {
		if (this.bounds.contains(tx, ty)) {
			this.tileMatrix[ty - this.bounds.y][tx - this.bounds.x] = ti;
		}
	}

	/**
	 * Is an extension of the super.setBounds, that is used to set the offset when the layer is created.
	 * 
	 * @param x
	 * @param y
	 */
	public void setOffset(int x, int y) {
		//		this.bounds.x = x;
		//		this.bounds.y = y;
		this.finalx = x;
		this.finaly = y;
	}

	//    /**
	//     * Returns the tile at the specified position.
	//     *
	//     * @param tx Tile-space x coordinate
	//     * @param ty Tile-space y coordinate
	//     * @return tile at position (tx, ty) or <code>null</code> when (tx, ty) is
	//     *         outside this layer
	//     */
	//    public Tile getTileAt(int tx, int ty) {
	//        return (bounds.contains(tx, ty)) ?
	//                map[ty - bounds.y][tx - bounds.x] : null;
	//    }
	//	/**
	//     * Removes any occurences of the given tile from this map layer. If layer
	//     * is locked, an exception is thrown.
	//     *
	//     * @param tile the Tile to be removed
	//     */
	//    public void removeTile(Tile tile) {
	//        for (int y = 0; y < bounds.height; y++) {
	//            for (int x = 0; x < bounds.width; x++) {
	//                if (map[y][x] == tile) {
	//                    setTileAt(x + bounds.x, y + bounds.y, null);
	//                }
	//            }
	//        }
	//    }
	//	/**
	//     * Checks to see if the given Tile is used anywhere in the layer.
	//     *
	//     * @param t a Tile object to check for
	//     * @return <code>true</code> if the Tile is used at least once,
	//     *         <code>false</code> otherwise.
	//     */
	//    public boolean isUsed(Tile t) {
	//        for (int y = 0; y < bounds.height; y++) {
	//            for (int x = 0; x < bounds.width; x++) {
	//                if (map[y][x] == t) {
	//                    return true;
	//                }
	//            }
	//        }
	//        return false;
	//    }

}
